package core;

import java.util.ArrayList;

import functions.Function;
import functions.FunctionIF;

public class SecantMethod extends Method {

	private double initialX1;
	private double initialX2;
	public SecantMethod(int numOfIteration, double precision , double initX1 , double initX2) {
		super(numOfIteration, precision);
		initialX1 = initX1;
		initialX2 = initX2;
	}

	@Override
	public ArrayList<Point> run(Function f) {
		ArrayList<Point> res = new ArrayList<Point>();
		double initialY1 = f.eval(initialX1);
		if(Math.abs(initialY1)>2)
		{
			initialX1 = estimateX(f);
			initialX2 = initialX1 + 0.1;
			initialY1 = f.eval(initialX1);
		}
		Point p1 = new Point(initialX1,initialY1);
		Point p2 = new Point(initialX2,f.eval(initialX2));
		res.add(p1);
		res.add(p2);
		while(Math.abs(p2.getY())>precision && res.size()<numOfIteration)
		{
			double newX = p2.getX() - ((p2.getY()*(p2.getX()-p1.getX()))/(p2.getY()-p1.getY()));
			p1 = p2;
			p2 = new Point(newX , f.eval(newX));
			res.add(p2);
		}
		finalX = p2.getX();
		return res;
	}

	private double estimateX(Function f) {
		for(int i=-100;i<101;i++)
		{
			if(Math.abs(f.eval(i))<1.5)
				return i;
		}
		return 0;
	}
	@Override
	public double getErrorBound() {
		FunctionIF firstDriv = function.diff();
		FunctionIF secDriv = firstDriv.diff();
		return Math.pow(secDriv.eval(finalX)/(2*firstDriv.eval(finalX)), 0.618);
	}

}
